<template>
  {{ obj1 }}
  {{ obj2 }}
  {{ cusRef }}
  <h1 ref="h1">hihihi</h1>
  <button @click="update">update</button>
</template>
<script setup lang="ts">
import { customRef, isRef, Ref, ref, shallowRef, triggerRef } from 'vue'

// ref 参数为对象或原始值，返回值为被包裹的 Ref 对象，可以通过 value 属性操作值
// ref 返回值为深度响应式对象，会深度监听修改操作并更新页面视图
// const refVal = ref<T>(value) 泛型约束创建 Ref 对象
// ref.value 操作 value 值
// Ref 接口，约束 Ref 对象的类型
// const refVal: Ref<T> = ref(value)

// shallowRef 参数为对象或原始值，返回值为被包裹的 Ref 对象，可以通过 value 属性操作值
// shallowRef 返回值为浅响应式对象，仅会监听修改 value 属性的操作并更新页面视图
// const shallowRefVal = shallowRef<T>(value)
// shallowRefVal.value
// 注意：同一步操作中，如果通过操作 ref 和 shallowRef 其中 ref 操作会触发页面更新
// 页面会同步 shallowRef 值更新

// triggerRef 参数为 Ref 对象，会直接触发一次页面视图更新该 Ref 对象的新值
// triggerRef(Ref)

// isRef 参数为对象，返回是否为 Ref 对象的布尔值
// isRef(obj)

// customRef 参数为回调函数,回调参数为 track trigger 函数，返回值为对象
// 在返回值对象中，实现 get 和 set 用于操作及访问值，并采用参数 track trigger 函数实现响应式数据
// customRef 一般用于自定义 Ref 对象,常在创建 Ref 对象的函数内调用
// 对自定义 Ref 对象的 get set 调用 track trigger 实现响应式数据,且可以添加其他的 get set 行为
// customRef 如果需要深度响应需要在 set 和 get 中实现递归调用
// 常用于实现 Ref 对象的防抖功能(设置定时器,一定间隔内才触发行为)
// customRef((track: function, trigger: function): Ref => {
//   return {
//   set(newVal) {
//     调用 trigger 方法
//     trigger()
//     val 值为创建 Ref 对象的函数的参数
//     val = newVal
//   },
//   get() {
//     调用 track 方法
//     track()
//     return val
//   }
// }
// })

// 在 html 标签中使用 ref 设置属性,可以在 js 中获取该 ref 引用的 DOM 元素
// 注意:需要等待页面渲染完成时,才能访问到 DOM 元素
// <h1 ref="h1"></h1>
// const h1 = ref<HTMLElement> 需页面渲染完成时才能获取
// DOM 数据的获取需保持常量命名和 html 中 ref 属性值为一致,不用传参

interface Obj {
  name: string
}
// ref 泛型定义 obj 类型
// const obj = ref<Obj>({ name: 'Tom'})
// Ref 接口泛型定义 obj类型
const obj1: Ref<Obj> = ref({ name: 'Tom' })

// shallowRef 浅层响应，即拦截操作 ref.value 这一层的行为触发页面更新
const obj2: Ref<Obj> = shallowRef({ name: 'Mike' })

// ref 获取 DOM 元素,其命名与 ref 属性值一致
const h1 = ref<HTMLElement>()
// setup 时,页面 DOM 结构不存在,不能获取
console.log(h1)

// getCusRef 函数,将参数转化为自定义的 Ref 对象
function getCusRef<T>(val: T) {
  return customRef((track, trigger) => {
    return {
      set(newVal: T) {
        trigger()
        val = newVal
      },
      get() {
        track()
        console.log('get')
        return val
      }
    }
  })
}
const cusRef = getCusRef<Obj>({name: 'Tom'})
const update = () => {
  // // 当修改 ref 和 shallowRef 操作在同一步时，会影响 shallowRef
  // // 因为操作 ref 时会触发页面更新，此时会将 shallowRef 修改的数据同时更新到页面上
  // // obj1.value.name += '+'
  // obj2.value.name += '='
  // // triggerRef 会将参数 ref 对象强制进行页面依赖的更新
  // triggerRef(obj2)
  // // isRef 判断是否为 ref 对象
  // console.log(isRef(obj2))
  // console.log(obj1)
  // // 页面渲染完成,可以获取到对对应的 DOM 元素
  // console.log(h1)
  // customRef 自定义 Ref 对象基础也为浅响应式对象,如果需要深度响应,需要递归调用
  cusRef.value = {name: 'Jerry'}
}
</script>
<style scoped></style>
